package com.bjpowernode.config.filter;

import com.bjpowernode.constant.Constants;
import com.bjpowernode.model.TUser;
import com.bjpowernode.result.CodeEnum;
import com.bjpowernode.result.R;
import com.bjpowernode.service.RedisService;
import com.bjpowernode.util.JSONUtils;
import com.bjpowernode.util.JWTUtils;
import com.bjpowernode.util.ResponseUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Component
public class TokenVerifyFilter extends OncePerRequestFilter {

	@Resource
	private RedisService redisService;

	// springboot框架的ioc容器中已经创建好了该线程池，可以注入直接使用
	@Autowired
	private ThreadPoolTaskExecutor threadPoolTaskExecutor;

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		String requestURI = request.getRequestURI();
		if (requestURI.equals(Constants.LOGIN_URI)) {

			// 登录的时候还没有生成jwt，此时不需要验证jwt，直接放行即可，可以让filter链继续执行，执行下一个filter
			filterChain.doFilter(request, response);

		} else {

			// 拿到前端传过来的jwt（token），这个jwt一般都通过header传过来
			String token = request.getHeader("Authorization");

			if (!StringUtils.hasText(token)) {

				// 登录未成功的统一结果
				R result = R.FAIL(CodeEnum.TOKEN_IS_EMPTY);

				// 把R对象转成json
				String resultJson = JSONUtils.toJSON(result);

				// 把R以json返回给前端
				ResponseUtils.write(response, resultJson);

				return;
			}

			// 校验传过来的token是否被篡改过
			if (!JWTUtils.verifyJWT(token)) {
				// 执行到这里，那我们向前端返回json就行了
				R result = R.FAIL(CodeEnum.TOKEN_IS_NONE_MATCH);

				// 把R对象转成json
				String resultJSON = JSONUtils.toJSON(result);

				// 把json写出去，写到浏览器
				ResponseUtils.write(response, resultJSON);
				return;
			}

			// 怎么拿到用户的id？反写解析jwt，从jwt中解析出用户的id
			String userJSON = JWTUtils.parseJWT(token);
			TUser tUser = JSONUtils.toBean(userJSON, TUser.class);
			Integer userId = tUser.getId();
			String redisToken = (String) redisService.getValue(Constants.REDIS_JWT_KEY + userId);

			if (!StringUtils.hasText(redisToken)) {
				// jwt过期了
				// 执行到这里，那我们向前端返回json就行了
				R result = R.FAIL(CodeEnum.TOKEN_IS_EXPIRED);

				// 把R对象转成json
				String resultJSON = JSONUtils.toJSON(result);

				// 把json写出去，写到浏览器
				ResponseUtils.write(response, resultJSON);
				return;
			}

			if (!token.equals(redisToken)) {
				// token不合法
				R result = R.FAIL(CodeEnum.TOKEN_IS_ERROR);

				String resultJson = JSONUtils.toJSON(result);

				ResponseUtils.write(response, resultJson);

				return;
			}

			// 都验证通过了，没有问题了，需要告诉spring security框架，这样spring security框架才知道该jwt是已经登录过的
			UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(tUser,
					tUser.getPassword(), tUser.getAuthorities());
			SecurityContextHolder.getContext().setAuthentication(authenticationToken);

			// 刷新一下token（异步处理,new一个线程去执行）
//            new Thread(()->{
//            	
//                String rememberMe = request.getHeader("rememberMe");
//                if (Boolean.parseBoolean(rememberMe)) {
//                    redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.EXPIRE_TIME, TimeUnit.SECONDS);
//                } else {
//                    redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS);
//                }
//                
//            }).start();

			// 异步处理（更好的方式，使用线程池去执行）
			threadPoolTaskExecutor.execute(() -> {

				String rememberMe = request.getHeader("rememberMe");
				if (Boolean.parseBoolean(rememberMe)) {
					redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.EXPIRE_TIME,
							TimeUnit.SECONDS);
				} else {
					redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.DEFAULT_EXPIRE_TIME,
							TimeUnit.SECONDS);
				}

			});

			// 下面就是filter链继续执行，执行下一个filter
			filterChain.doFilter(request, response);
		}
	}
}
